package com.xbongbong.paas.business.rule;

import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.enums.BusinessRuleExecuteEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.RuleOperationEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.FilterConditionsPoJo;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.pojo.ActiveRulePoJo;
import com.xbongbong.paas.pojo.BusinessRulesPoJo;
import com.xbongbong.paas.pojo.OperationsPojo;
import com.xbongbong.paas.pojo.RulePoJo;
import com.xbongbong.paas.pojo.dto.InactiveRuleDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.pro.businessrule.pojo.BusinessRuleConditionPojo;
import com.xbongbong.pro.businessrule.pojo.BusinessRuleInfoPojo;
import com.xbongbong.pro.businessrule.pojo.dto.OperationDTO;
import com.xbongbong.pro.businessrule.pojo.dto.OperatorBatchDTO;
import com.xbongbong.pro.businessrulelog.pojo.BusinessRuleLogSaveDTO;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.form.pojo.RuleTargetPojo;
import com.xbongbong.pro.form.pojo.vo.FormBusinessRuleVO;
import com.xbongbong.pro.rabbitmq.producer.BusinessRuleProducer;
import com.xbongbong.saas.domain.entity.WorkOrderExplainEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;


/**
 * @author: wufeng
 * @date: 2018/12/28 16:42
 * @desrcption: 表单数据失效规则
 */
@Component
public class FormDataInactiveRuleHelp extends AbstractRuleHelp {

    private static final Logger LOG = LoggerFactory.getLogger(FormDataInactiveRuleHelp.class);

    @Resource
    @Lazy
    private BusinessRuleProducer businessRuleProducer;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private BusinessRuleUserPermissionHelp businessRuleUserPermissionHelp;
    @Resource
    private BusinessRuleInfoService businessRuleInfoService;
    @Resource
    private BusinessRuleConditionHelp businessRuleConditionHelp;

    /**
     * 批量删除触发
     * @param inactiveRuleDTO
     */
    public void inactiveRuleBatch(InactiveRuleDTO inactiveRuleDTO){
        executeRule(inactiveRuleDTO);
    }



    /**
     * 执行规则
     * @param inactiveRuleDTO
     */
    public void executeRule(InactiveRuleDTO inactiveRuleDTO) {
        try {
            String corpid = inactiveRuleDTO.getCorpid();
            if (businessRuleUserPermissionHelp.validateUsePermission(corpid)) {
                // 不是旗舰版，并且白名单不为空且不在白名单内
                return;
            }
            PaasFormDataEntity paasFormDataEntity = inactiveRuleDTO.getPaasFormDataEntity();
            List<BusinessRulesPoJo> businessRules = inactiveRuleDTO.getRuleList();
            Long formId = paasFormDataEntity.getFormId();
            Long dataId = paasFormDataEntity.getId();
            Integer excess = 0;
            if (CollectionsUtil.isEmpty(businessRules)) {
                FormBusinessRuleVO businessRuleVO = businessRuleInfoService.get(corpid, paasFormDataEntity.getFormId(), inactiveRuleDTO.getBusinessType(), inactiveRuleDTO.getSaasMark(), 0);
                businessRules = businessRuleVO.getBusinessRule();
                excess = businessRuleVO.getExcess();
                if (businessRuleVO.getFormulaLimit()) {
                    return;
                }
            }
            if (CollectionsUtil.isEmpty(businessRules)) {
                return;
            }
            if (Objects.isNull(excess) || excess > 0) {
                return;
            }
            if(CollectionsUtil.isNotEmpty(businessRules)){
                Integer size = businessRules.size();
                inactiveRuleDTO.setBusinessRuleSize(size);
                Set<Long> formIdList = new HashSet<>();
                Set<Long> workOrderFormIdList = new HashSet<>();
                // 获取表单id
                getFormId(businessRules, workOrderFormIdList, formIdList);
                Map<String, FieldAttrEntity> explainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                inactiveRuleDTO.getExplainList().forEach(item -> {
                    explainMap.put(item.getAttr(), item);
                });
                ProFormHelp.setDataIdAttr(explainMap);
                // 获取表单解释
                Map<Long, PaasFormExplainEntity> formExplainMap = proFormHelp.getFormExplainMap(formIdList, corpid);
                Map<Long, WorkOrderExplainEntity> workOrderExplainMap = proFormHelp.getWorkOrderFormExplainMap(workOrderFormIdList, corpid);
                List<OperationDTO> operationDtoList = new ArrayList<>();
                for (BusinessRulesPoJo businessRulesPoJo : businessRules) {
                    ActiveRulePoJo inactiveRulePoJo = businessRulesPoJo.getInactiveRule();
                    inactiveRuleDTO.setBusinessRuleInfoId(businessRulesPoJo.getBusinessRuleId());
                    boolean flag = executeRule(inactiveRuleDTO, inactiveRulePoJo, formExplainMap, workOrderExplainMap, explainMap, paasFormDataEntity, operationDtoList);
                    if (!flag) {
                        // 记录日志
                        RuleTargetPojo target = inactiveRulePoJo.getRule().getTarget();
                        BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(inactiveRuleDTO.getSaasMark(), inactiveRuleDTO.getBusinessType(), formId, inactiveRuleDTO.getDataId(),
                                corpid, inactiveRuleDTO.getLoginUser(), inactiveRuleDTO.getPlatform(), inactiveRuleDTO.getHttpHeader(), inactiveRuleDTO.getBrowserInfo(),
                                INACTIVE_BUSINESS_RULE_TYPE, target, inactiveRuleDTO.getIp(), inactiveRuleDTO.getLocale());
                        setLogger(businessRuleLogSaveDTO, businessRulesPoJo.getBusinessRuleId(), inactiveRulePoJo.getRule().getOperationType(), BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getMessage(), BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getCode(),
                                target, inactiveRulePoJo.getRule().getOperationType(), 0, 1);
                        continue;
                    }
                }
                if (CollectionsUtil.isNotEmpty(operationDtoList)) {
                    OperatorBatchDTO operatorBatchDTO = new OperatorBatchDTO(operationDtoList, inactiveRuleDTO.getSaasMark(), inactiveRuleDTO.getBusinessType(), formId, dataId,
                            corpid, inactiveRuleDTO.getLoginUser(), inactiveRuleDTO.getPlatform(),
                            inactiveRuleDTO.getHttpHeader(), inactiveRuleDTO.getBrowserInfo(), inactiveRuleDTO.getIp(), inactiveRuleDTO.getLocale(), inactiveRuleDTO.getIsImport());
                    sendMessage(operatorBatchDTO);
                }
            }

        }catch (Exception e) {
            LOG.error("formDataActiveRuleHelp.validateDataByActiveRule生效规则校验失败：", e);
        }
    }

    /**
     * 执行规则
     * @param inactiveRuleDTO
     * @param inactiveRulePoJo
     * @param formExplainMap
     * @param workOrderExplainMap
     * @param explainMap
     * @param paasFormDataEntity
     * @throws XbbException
     */
    public boolean executeRule(InactiveRuleDTO inactiveRuleDTO, ActiveRulePoJo inactiveRulePoJo, Map<Long, PaasFormExplainEntity> formExplainMap,
                            Map<Long, WorkOrderExplainEntity> workOrderExplainMap, Map<String, FieldAttrEntity> explainMap,
                            PaasFormDataEntity paasFormDataEntity, List<OperationDTO> operationDTOList) throws XbbException {
        String corpid = inactiveRuleDTO.getCorpid();
        Long formId = inactiveRuleDTO.getPaasFormDataEntity().getFormId();
        Long businessRuleId = inactiveRuleDTO.getBusinessRuleInfoId();
        Integer reason = BusinessRuleExecuteEnum.PRODUCER_ERROR.getCode();
        Integer operationType = 0;
        RuleTargetPojo target = new RuleTargetPojo();
        try {
            BusinessRuleInfoPojo businessRuleInfoPojo = new BusinessRuleInfoPojo();
            businessRuleInfoPojo.setThisExplainMap(explainMap);
            businessRuleInfoPojo.setFormExplainMap(formExplainMap);
            businessRuleInfoPojo.setWorkOrderExplainMap(workOrderExplainMap);
            businessRuleInfoPojo.setBusinessType(inactiveRuleDTO.getBusinessType());
            businessRuleInfoPojo.setSaasMark(inactiveRuleDTO.getSaasMark());
            businessRuleInfoPojo.setCorpid(corpid);
            if (Objects.isNull(inactiveRulePoJo) || Objects.equals(inactiveRulePoJo.getEnable(), 0)) {
                return true;
            }
            OperationDTO operationDTO = new OperationDTO();
            BeanUtil.copyProperties(inactiveRuleDTO, operationDTO);
            RulePoJo rulePoJo = inactiveRulePoJo.getRule();
            if (Objects.nonNull(rulePoJo)) {
                target = rulePoJo.getTarget();
                businessRuleInfoPojo.setRuleTargetPojo(target);
                businessRuleInfoPojo.setOperationType(rulePoJo.getOperationType());
                businessRuleInfoPojo.setFormId(paasFormDataEntity.getFormId());
                // 校验下前置条件
                boolean flag = businessRuleConditionHelp.validatePreCondition(rulePoJo.getPreConditions(), paasFormDataEntity, businessRuleInfoPojo);
                if (!flag) {
                    // 返回用于记录日志
                    return false;
                }
                operationDTO.setOperationType(rulePoJo.getOperationType());
                operationDTO.setTarget(target);
                operationDTO.setFormId(formId);
                // 高级模式和简易版模式
                operationDTO.setType(inactiveRulePoJo.getType());
                // 过滤掉为空的数据
                List<OperationsPojo> operationList = rulePoJo.getOperations();
                operationType = rulePoJo.getOperationType();
                operationDTO.setOperations(operationList);
                Map<String, FieldAttrEntity> targetExplainMap = getTargetExplainMap(businessRuleInfoPojo);
                operationDTO.setBusinessRuleInfoId(inactiveRuleDTO.getBusinessRuleInfoId());
                operationDTO.setBusinessRuleType(2);
                if (Objects.equals(RuleOperationEnum.ONLY_INSERT.getType(), rulePoJo.getOperationType()) && Objects.equals(SaasMarkEnum.PAAS.getCode(), target.getLinkSaasMark())) {
                    operationDTO.setPaasFormDataEntity(paasFormDataEntity);
                    operationDTO.setTargetExplain(null);
                    operationDTO.setThisExplain(null);
                    operationDTOList.add(operationDTO);
                } else {
                    List<FilterConditionsPoJo> filterConditions = rulePoJo.getFilterConditions();
                    businessRuleInfoPojo.setTargetExplainMap(targetExplainMap);
                    // 获取关联数据的集合
                    getFormDataMap(paasFormDataEntity, inactiveRuleDTO.getExplainList(), businessRuleInfoPojo);
                    // 过滤条件整合
                    BusinessRuleConditionPojo businessRuleConditionPojo = businessRuleConditionHelp.getConditionList(filterConditions, paasFormDataEntity, businessRuleInfoPojo);

                    List<ConditionsEntityExt> conditionList = businessRuleConditionPojo.getConditionList();

                    if (Objects.equals(target.getLinkBusinessType(), XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode())) {
                        conditionList.add(new ConditionsEntityExt(FieldTypeEnum.LOG_TYPE.getAlias(),"",FieldTypeEnum.LOG_TYPE.getType(), ConditionEnum.EQUAL.getSymbol(), Collections.singletonList(0)));
                    }
                    List<ConditionsEntityExt> subConditionList = businessRuleConditionPojo.getSubConditionList();
                    // 没有条件不执行更新，但是不影响插入
                    if (CollectionsUtil.isEmpty(conditionList) && CollectionsUtil.isEmpty(subConditionList)) {
                        LOG.error("not have condition");
                        return true;
                    }
                    // 获取权限内的数据

                    List<List<ConditionsEntityExt>> shouldConditionList = new ArrayList<>();
                    // 更新
                    operationDTO.setFilterConditionList(filterConditions);
                    operationDTO.setPaasFormDataEntity(paasFormDataEntity);
                    operationDTO.setTargetExplain(null);
                    operationDTO.setThisExplain(null);
                    operationDTO.setShouldConditionList(shouldConditionList);
                    operationDTO.setConditionList(conditionList);
                    operationDTO.setSubConditionList(subConditionList);
                    operationDTO.setAttr(businessRuleConditionPojo.getAttr());
                    operationDTO.setFormDataMap(businessRuleInfoPojo.getFormDataMap());
                    operationDTOList.add(operationDTO);
                }
            }
        } catch (XbbException e) {
            // 记录日志
            BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(inactiveRuleDTO.getSaasMark(), inactiveRuleDTO.getBusinessType(), formId, inactiveRuleDTO.getDataId(),
                   INACTIVE_BUSINESS_RULE_TYPE, corpid, inactiveRuleDTO.getLoginUser(), inactiveRuleDTO.getPlatform(), inactiveRuleDTO.getHttpHeader(), inactiveRuleDTO.getBrowserInfo(), inactiveRuleDTO.getIp(), inactiveRuleDTO.getLocale());
            setLogger(businessRuleLogSaveDTO, businessRuleId, operationType, e.getMsg(), reason, target, 0, 0, 0);
        } catch (Exception e) {
            LOG.error("FormDataInactiveRuleHelp.executeRule fail：", e);
        }
        return true;
    }
    /**
     * 操作saas中业务
     * @param operatorBatchDTO
     * @throws XbbException
     */
    @Override
    public void sendMessage(OperatorBatchDTO operatorBatchDTO) throws XbbException {
        businessRuleProducer.sendMessage(operatorBatchDTO);
    }


}
